#ifndef FIRMS_H_INCLUDED
#define FIRMS_H_INCLUDED
#include <math.h>
#include "Bank.h"

// Short declarations to allow classes to be recognized by each other
class DownstreamFirm;
class UpstreamFirm;
class Bank;

// Definition of superclass Firm
class Firm {
    public:
    virtual void initialize (double input[]); // Initializer
    virtual void calcQuantities (); // Update of firm indicators and quantities to be bought and sold
    virtual void calcInterestRates (); // Calculate interest rates
    virtual void calcNetWorth (); // Calculate profit and update net worth
    virtual void goBankrupt (); // Pass debts to partners when going bankrupt

    // Accessor methods
    double getNetWorth ();
    double getProfit ();
    double getTradeIR ();
    double getBankIR ();
    double getLoan ();
    double getLeverage ();
    bool checkInsolvency ();

    protected:
    Firm (); // Constructor
    double netWorth, profit, numWorkers, wage, bankLoan, leverage; // Firm indicators
    double sellQuant, sellPrice; // Quantity and price of goods to be sold
    double phi, beta, deltaD, gamma, deltaU, alpha, sigma, theta; // Functions parameters
    double tradeIR, bankIR; // Interest rate on the commercial loans and on bank loans

    // Pointers to partners in the network
    Bank *partnerBank;
};

// Definition of class DownstreamFirm, which inherits variables and methods
// from the superclass Firm
class DownstreamFirm : public Firm {
    public:
    DownstreamFirm (); // Constructor
    void initialize (double input[]); // Initializer

    void calcQuantities (double sp); // Update of firm indicators and quantities to be bought and sold
    void calcInterestRates (); // Calculate interest rates
    void calcNetWorth (); // Calculate profit and update net worth
    void goBankrupt (); // Pass debts to partners when going bankrupt

    // Methods to deal with the pointers
    void setUstrPartner (UpstreamFirm *p);
    void delUstrPartner ();
    void makeUstrPartnerDelMe ();
    void setBankPartner (Bank *b);
    void delBankPartner ();
    void makeBankPartnerDelMe ();

    // Accessor methods
    double getBuyQuant ();
    double getProduction ();
    bool gotNoUstrPartner ();
    bool gotNoBankPartner ();

    private:
    double buyQuant, buyPrice; // Quantity and price of goods to be bought

    // Pointers to partners in the network
    UpstreamFirm *partnerFirm;
    Bank *partnerBank;
};

// Definition of class UpstreamFirm, which inherits variables and methods from
// the superclass Firm
class UpstreamFirm : public Firm {
    public:
    UpstreamFirm (); // Constructor
    void initialize (double input[]); // Initializer
    void calcQuantities (); // Update of firm indicators and quantities to be bought and sold
    void calcInterestRates (); // Calculate interest rates
    void calcNetWorth (); // Calculate profit and update net worth
    void goBankrupt (); // Pass debts to partners when going bankrupt

    // Methods to deal with the pointers
    void addDstrPartner (DownstreamFirm *p);
    void delDstrPartner (DownstreamFirm *p);
    void setBankPartner (Bank *b);
    void delBankPartner ();
    void makeBankPartnerDelMe ();

    // Accessor methods
    void incrBadDebt (double bd);
    bool gotNoBankPartner ();
    int getNumPartners ();

    private:
    double badDebt;

    int numDstrPartners;
    // Pointers to partners in the network
    DownstreamFirm **partnerFirms;
    Bank *partnerBank;
};

#endif // FIRMS_H_INCLUDED
